package homework

import (
	"errors"
	"reflect"
	"strings"
)

var errInvalidEntity = errors.New("invalid entity")

func InsertStmt(entity interface{}) (string, []interface{}, error) {

	// val := reflect.ValueOf(entity)
	// typ := val.Type()
	// 检测 entity 是否符合我们的要求
	// 我们只支持有限的几种输入

	// 使用 strings.Builder 来拼接 字符串
	// bd := strings.Builder{}

	// 构造 INSERT INTO XXX，XXX 是你的表名，这里我们直接用结构体名字

	// 遍历所有的字段，构造出来的是 INSERT INTO XXX(col1, col2, col3)
	// 在这个遍历的过程中，你就可以把参数构造出来
	// 如果你打算支持组合，那么这里你要深入解析每一个组合的结构体
	// 并且层层深入进去

	// 拼接 VALUES，达成 INSERT INTO XXX(col1, col2, col3) VALUES

	// 再一次遍历所有的字段，要拼接成 INSERT INTO XXX(col1, col2, col3) VALUES(?,?,?)
	// 注意，在第一次遍历的时候我们就已经拿到了参数的值，所以这里就是简单拼接 ?,?,?

	// return bd.String(), args, nil
	if entity == nil {
		return "", nil, errInvalidEntity
	}
	typeOf := reflect.TypeOf(entity)
	valueOf := reflect.ValueOf(entity)
	if reflect.Ptr == typeOf.Kind() {
		typeOf = typeOf.Elem()
		valueOf = valueOf.Elem()
	}
	if typeOf.Kind() != reflect.Struct {
		return "", nil, errInvalidEntity
	}
	numField := typeOf.NumField()
	if 0 == numField {
		return "", nil, errInvalidEntity
	}

	args := make([]interface{}, 0, numField)
	bd := strings.Builder{}
	bd.WriteString("INSERT INTO `")
	bd.WriteString(typeOf.Name())
	bd.WriteString("`(")
	visitName := make([]string, 0, numField)
	if 1 == numField {
		visitName = append(visitName, typeOf.Field(0).Type.Name())
		args = append(args, valueOf.Field(0).Interface())
	} else {
		for i := 0; i < numField; i++ {
			visit1, args1, err := insertFields(typeOf.Field(i), valueOf.Field(i), visitName)
			if err != nil {
				return "", nil, err
			}
			if visit1 == nil {
				continue
			}
			visitName = visit1
			args = append(args, args1...)
		}
	}

	for i := 0; i < len(visitName); i++ {
		bd.WriteString("`")
		bd.WriteString(visitName[i])
		bd.WriteString("`")
		if len(visitName)-1 > i {
			bd.WriteString(",")
		}
	}

	bd.WriteString(") VALUES(")
	for i := 0; i < len(args); i++ {
		bd.WriteString("?")
		if len(args)-1 > i {
			bd.WriteString(",")
		}
	}
	bd.WriteString(");")
	return bd.String(), args, nil
}

func insertFields(f reflect.StructField, v reflect.Value, visit []string) ([]string, []interface{}, error) {
	args := make([]interface{}, 0, 1)
	t := f.Type
	if t.Kind() == reflect.Struct && f.Type.PkgPath() != "database/sql" {
		//解析所有字段
		numField := t.NumField()
		if numField > 0 {
			for i := 0; i < numField; i++ {
				visit1, args1, err := insertFields(t.Field(i), v.Field(i), visit)
				if err != nil {
					return nil, nil, err
				}
				if visit1 == nil {
					continue
				}
				visit = visit1
				args = append(args, args1...)
			}
			return visit, args, nil
		}
	}
	for _, s := range visit {
		if f.Name == s {
			return nil, args, nil
		}
	}
	return append(visit, f.Name), append(args, v.Interface()), nil
}
